#pragma once

#include <memory>
#include <list>

#include "MyPthread/Log.hpp"
#include "Common.hpp"
#include "InetAddr.hpp"

using namespace LogModule;
using namespace ThreadModule;

class UserInterface
{
public:
    virtual ~UserInterface() = default;
    virtual void SendTo(int sockfd, const std::string &message) = 0;
    virtual bool operator==(const InetAddr &u) = 0;
    virtual std::string Id() = 0;
};

class User : public UserInterface
{
public:
    User(InetAddr addr) : _addr(addr)
    {
    }
    void SendTo(int sockfd, const std::string &message) override
    {
        int n = ::sendto(sockfd, message.c_str(), message.size() , 0, CONV(_addr.NetAddr()), _addr.NetAddrLen());
        if(n < 0)
        {
            LOG(LogLevel::ERROR) << "sendto eroror" << _addr.Addr();

        }
        LOG(LogLevel::DEBUG) << "send message to " << _addr.Addr() << " info: " << message;

    }
    bool operator==(const InetAddr &u) override
    {
        return _addr == u;
    }
    std::string Id() override
    {
        return _addr.Ip()+ ":"+std::to_string(_addr.Port());
    }

private:
    InetAddr _addr;
};

// 对用户消息进行路由
//  UserManager 把所有的用户先管理起来！
//  观察者模式！observer
class UserManager
{
public:
    bool AddUser(const InetAddr &user)
    {
        LockGuard lockguard(_mutex);
        for (auto &e : _online_user)
        {
            if (*e == user)
            {
                LOG(LogLevel::DEBUG) << "用户-> " << e->Id()<<"已存在";
                return false;
            }
        }
        auto newuser = std::make_shared<User>(user);
        _online_user.push_back(newuser);

        LOG(LogLevel::DEBUG) << "添加用户-> " << newuser->Id();
        PrintUser();

        return true;
    }
    void PrintUser()
    {
        for (auto user : _online_user)
        {
            LOG(LogLevel::DEBUG) << "在线用户-> " << user->Id();
        }
    }
    void Router(int sockfd, const std::string &message)
    {
        LockGuard lockguard(_mutex);
        for (auto &e : _online_user)
        {
            e->SendTo(sockfd,message);
        }
    }
    void DelUser(const InetAddr& id)
    {
        auto pos = std::remove_if(_online_user.begin(),_online_user.end(),
                                [&id](std::shared_ptr<UserInterface>& user){
                                    return *user ==  id;
                                });
        _online_user.erase(pos,_online_user.end());
        PrintUser();
    }
private:
    std::list<std::shared_ptr<UserInterface>> _online_user;
    Mutex _mutex;
};
